package com.xishu.socket;

import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.Weighers;
import com.xishu.bo.LineUpCodeResponse;
import com.xishu.config.Constant;
import com.xishu.entity.shop.LineUp;
import com.xishu.entity.shop.LineUpConfig;
import com.xishu.service.LineUpService;
import com.xishu.util.Tools;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class WebSocketService implements Tools {
    private static Logger logger = LoggerFactory.getLogger(WebSocketService.class);
    private Map<String, List<WebSocket>> socketMap = new ConcurrentLinkedHashMap.Builder<String, List<WebSocket>>().maximumWeightedCapacity(1000).weigher(Weighers.singleton()).build();

    private static WebSocketService instance = new WebSocketService();

    private WebSocketService() {
    }

    public static WebSocketService getInstance() {
        return instance;
    }

    /**
     * 获取web socket
     *
     * @param id
     * @return
     */
    public List<WebSocket> getSocket(String id) {
        logger.info("id is {}", id);
        List<WebSocket> webSockets = null;
        try {
            for (Map.Entry<String, List<WebSocket>> entry : socketMap.entrySet()) {
                String key = entry.getKey();
                List<WebSocket> value = entry.getValue();
                logger.info("key is {}", key);
            }

            webSockets = socketMap.get(id);
            if (webSockets == null) {
                return new ArrayList<>();
            }
        } catch (Exception e) {
            logger.error("e", e);
        }
        return webSockets;
    }

    /**
     * 新注册会话
     *
     * @param key
     * @param webSocket
     */
    public synchronized void addSocket(String key, WebSocket webSocket) {
        logger.info("socket id is {}", webSocket.getSocketId());
        try {
            if (socketMap.containsKey(key)) {
                logger.info("will append the session");
            }

            List<WebSocket> socketList = socketMap.get(key);

            if (socketList == null) {
                socketList = new ArrayList<>();
                socketMap.put(key, socketList);
            }

            socketList.add(webSocket);

            logger.info("after add , key {} size is {}", key, socketList.size());
            logger.info(" after add ,map size is {}", socketMap.size());
        } catch (Exception e) {
            logger.error("e", e);
        }

    }

    /**
     * 注销
     *
     * @param webSocket
     */
    public synchronized void removeSocket(WebSocket webSocket) {
        String key = null;
        List<WebSocket> leftSocketList = null;
        logger.info("before remove map size is {}", socketMap.size());
        try {
            for (Map.Entry<String, List<WebSocket>> entry : socketMap.entrySet()) {
                List<WebSocket> socketList = entry.getValue();
                logger.info("the key is {}, list size is {}", entry.getKey(), socketList.size());

                Optional<WebSocket> webSocketOptional = getList(socketList).stream().filter(p -> equals(p.getSocketId(), webSocket.getSocketId())).findAny();

                //找到对应的KEY
                if (webSocketOptional.isPresent()) {
                    key = entry.getKey();
                    logger.info("find the key is {}", key);
                    logger.info("before remove list size is {}", socketList.size());
                    leftSocketList = getList(socketList).stream().filter(p -> !equals(p.getSocketId(), webSocket.getSocketId())).collect(Collectors.toList());
                    logger.info("after remove list size is {}", leftSocketList.size());
                    break;
                }
            }

            if (key != null) {
                logger.info("do the key {}", key);

                if (leftSocketList == null) {
                    logger.info("filter socket list is empty");
                } else if (leftSocketList.size() != 0) {
                    logger.info("key {} list size {}", key, leftSocketList.size());
                    socketMap.put(key, leftSocketList);
                } else {
                    logger.info("remove key {}", key);
                    socketMap.remove(key);
                }

            }

            logger.info("after remove map size is {}", socketMap.size());

        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 发送分店状态
     *
     * @param shopId
     * @param businessStatus
     */
    public void sendShopStatus(Long shopId, Boolean businessStatus) {
        try {
            List<WebSocket> webSocketList = WebSocketService.getInstance().getSocket(shopId + ":" + 0);
            for (WebSocket webSocket : webSocketList) {
                logger.info("shop status changed ");
                SocketMessage socketMessage = new SocketMessage();
                socketMessage.setType(Constant.SOCKET_TYPE_SHOP);
                socketMessage.setShopId(shopId);
                socketMessage.setStatus(0);
                socketMessage.setBusinessStatus(businessStatus);
                logger.info("will send web socket, {}", socketMessage);
                webSocket.sendMessage(JSONObject.fromObject(socketMessage).toString());
            }
        } catch (Exception e) {
            logger.error("e", e);
        }

    }

    public void sendLineUp(Long shopId) throws Exception {
        try {
            List<WebSocket> webSocketList = WebSocketService.getInstance().getSocket(shopId + ":" + 0);
            List<LineUpConfig> lineUpConfigList = LineUpService.getInstance().queryAllLineUpConfig(shopId);
            List<String> codeList = lineUpConfigList.stream().map(lineUpConfig -> lineUpConfig.getCode()).filter(code -> isNotEmpty(code)).collect(Collectors.toList());

            List<LineUpCodeResponse> lineUpCodeResponseList = codeList.stream().map(code -> {
                LineUp lineUp = new LineUp();
                lineUp.setShopId(shopId);
                lineUp.setCode(code);
                return LineUpService.getInstance().generateLineupCodeResponse(lineUp);
            }).filter(p -> p != null).collect(Collectors.toList());

            for (WebSocket webSocket : webSocketList) {
                logger.info("shop status changed ");
                SocketMessage socketMessage = new SocketMessage();
                socketMessage.setType(Constant.SOCKET_LINE_UP);
                socketMessage.setShopId(shopId);
                socketMessage.setStatus(0);
                socketMessage.setLineUpCodeResponseList(lineUpCodeResponseList);
                logger.info("will send web socket, {}", socketMessage);
                webSocket.sendMessage(JSONObject.fromObject(socketMessage).toString());
            }
        } catch (Exception e) {
            logger.error("e", e);
        }

    }

    /**
     * 发送订单数量
     *
     * @param shopId
     * @param count
     */
    public void sendKitchenOrderAudit(Long shopId, int count) {
        try {
            List<WebSocket> webSocketList = WebSocketService.getInstance().getSocket(shopId + ":" + 0);
            for (WebSocket webSocket : webSocketList) {
                logger.info("send kitchen order audit ");
                SocketMessage socketMessage = new SocketMessage();
                socketMessage.setType(Constant.SOCKET_TYPE_AUDIT_PRINT);
                socketMessage.setShopId(shopId);
                socketMessage.setStatus(0);
                socketMessage.setCount(count);
                logger.info("will send web socket  {} to client {}", socketMessage, webSocket.getSocketId());
                webSocket.sendMessage(JSONObject.fromObject(socketMessage).toString());
            }
        } catch (Exception e) {
            logger.error("e", e);
        }
    }
}
